import 'package:flutter/material.dart';

//Flutter 圆角矩形裁剪
void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            ClipRRect(
              // 设置8像素圆角，使按钮有圆角效果
              borderRadius: BorderRadius.circular(8.0),

              child: MaterialButton(
                onPressed: () {
                  // 按钮点击回调函数
                  print('按钮被点击了！');
                },
                color: Colors.blue, // 按钮背景颜色

                child: Text(
                  '圆角按钮',
                  style: TextStyle(color: Colors.white), // 按钮文字颜色
                ),
              ),
            ),
            SizedBox(height: 44),
            ClipRRect(
              // 设置12像素圆角，使卡片看起来更柔和
              borderRadius: BorderRadius.circular(12.0),

              child: Card(
                elevation: 4.0, // 卡片阴影深度
                // 卡片内部内容
                child: Padding(
                  // 内边距：所有方向16像素
                  padding: EdgeInsets.all(16.0),

                  child: Column(
                    // 垂直排列的子Widget
                    children: [
                      Text('卡片标题', style: TextStyle(fontSize: 18)), // 标题文本
                      SizedBox(height: 10), // 间距组件，高度10像素
                      Text('这是卡片内容...'), // 内容文本
                    ],
                  ),
                ),
              ),
            ),
            SizedBox(height: 44),
            ClipPath(
              clipper: ComplexClipper(),
              child: Container(width: 200, height: 200, color: Colors.blue),
            ),
            DynamicBorderRadiusExample(),
            //AnimatedClipPath(),
          ],
        ),
      ),
    );
  }
}

// 有状态的Widget，可以响应状态变化
class DynamicBorderRadiusExample extends StatefulWidget {
  @override
  _DynamicBorderRadiusExampleState createState() =>
      _DynamicBorderRadiusExampleState();
}

class _DynamicBorderRadiusExampleState
    extends State<DynamicBorderRadiusExample> {
  // 定义圆角半径的状态变量，初始值为10.0
  double _borderRadius = 10.0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // 滑块组件，用于动态调整圆角大小
        Slider(
          value: _borderRadius, // 当前值
          min: 0.0, // 最小值
          max: 50.0, // 最大值
          onChanged: (value) {
            // 值改变时的回调
            setState(() {
              // 调用setState更新UI
              _borderRadius = value; // 更新圆角半径
            });
          },
        ),

        // 使用动态圆角的ClipRRect
        ClipRRect(
          // 使用滑块的值作为圆角半径
          borderRadius: BorderRadius.circular(_borderRadius),

          child: Container(
            width: 200,
            height: 200,
            color: Colors.green, // 容器背景色
          ),
        ),
      ],
    );
  }
}

/**
 * 复杂裁剪器示例
 * 演示如何组合多个路径创建复杂形状
 * 这里演示挖空效果（差集运算）
 */
class ComplexClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    /// 创建主路径：覆盖整个区域的矩形
    final path = Path();
    path.addRect(Rect.fromLTWH(0, 0, size.width, size.height));

    /// 创建挖空路径：圆形
    Path circlePath = Path();
    circlePath.addOval(
      Rect.fromCircle(
        center: Offset(size.width / 2, size.height / 2), // 圆心在中心
        radius: 50, // 半径50
      ),
    );

    /// 使用Path.combine进行布尔运算
    /// PathOperation.difference: 差集操作，从主路径中减去圆形路径
    /// 效果：矩形中间有一个圆形洞
    return Path.combine(
      PathOperation.difference, // 运算类型：差集
      path, // 主路径
      circlePath, // 被减去的路径
    );
  }

  @override
  bool shouldReclip(ComplexClipper oldClipper) => false;
}

/**
 * 可动画的ClipPath组件
 * 使用StatefulWidget来管理动画状态
 */
class AnimatedClipPath extends StatefulWidget {
  @override
  _AnimatedClipPathState createState() => _AnimatedClipPathState();
}

/**
 * 动画ClipPath的状态类
 * 使用SingleTickerProviderStateMixin提供动画控制器
 */
class _AnimatedClipPathState extends State<AnimatedClipPath>
    with SingleTickerProviderStateMixin {
  /// 动画控制器：控制动画的启动、停止、重复等
  late AnimationController _controller;

  /// 动画值：在0到1之间变化，可以应用曲线
  late Animation<double> _animation;

  /**
   * 初始化状态
   * 在这里创建动画控制器和动画
   */
  @override
  void initState() {
    super.initState();

    /// 创建动画控制器
    /// duration: 动画时长
    /// vsync: 垂直同步信号，避免不必要的重绘
    _controller =
        AnimationController(
            duration: Duration(seconds: 2), // 2秒完成一次动画
            vsync: this, // 使用混入的TickerProvider
          )
          /// ..repeat(reverse: true): 连续执行动画，并且在完成后反向执行
          ..repeat(reverse: true);

    /// 创建曲线动画，使动画效果更自然
    _animation = CurvedAnimation(
      parent: _controller, // 父动画控制器
      curve: Curves.easeInOut, // 缓动曲线：开始和结束都缓慢
    );
  }

  /**
   * 构建组件
   * 使用AnimatedBuilder来响应动画值的变化
   */
  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _animation, // 监听的动画
      builder: (context, child) {
        /// 当动画值变化时，重新构建ClipPath
        return ClipPath(
          /// 使用动态的裁剪器，传入当前的动画值
          clipper: AnimatedWaveClipper(_animation.value),

          /// 被裁剪的容器
          child: Container(
            width: 300,
            height: 200,
            color: Colors.blue,

            /// 可选：在容器内显示当前动画值
            child: Center(
              child: Text(
                '动画值: ${_animation.value.toStringAsFixed(2)}',
                style: TextStyle(color: Colors.white, fontSize: 16),
              ),
            ),
          ),
        );
      },
    );
  }

  /**
   * 销毁状态
   * 必须释放动画控制器以避免内存泄漏
   */
  @override
  void dispose() {
    _controller.dispose(); // 释放动画控制器
    super.dispose();
  }
}

/**
 * 动态波浪裁剪器
 * 根据动画值动态改变波浪形状
 */
class AnimatedWaveClipper extends CustomClipper<Path> {
  /// animationValue: 动画值，范围0~1
  /// 用于控制波浪的起伏程度
  final double animationValue;

  /// 构造函数，接收动画值
  AnimatedWaveClipper(this.animationValue);

  @override
  Path getClip(Size size) {
    final path = Path();

    /// 移动到左下角偏上的位置
    path.lineTo(0, size.height * 0.7);

    /// 使用动画值控制控制点的y坐标
    /// 动画值为0时：控制点在基线位置
    /// 动画值为1时：控制点在底部位置
    /// 这样就能创建波浪起伏的效果
    var controlPoint = Offset(
      size.width / 2, // 控制点x坐标在中间
      size.height * (0.7 + 0.3 * animationValue), // 控制点y坐标随动画变化
    );

    /// 终点在右侧基线位置
    var endPoint = Offset(size.width, size.height * 0.7);

    /// 绘制贝塞尔曲线
    path.quadraticBezierTo(
      controlPoint.dx,
      controlPoint.dy, // 动态的控制点
      endPoint.dx,
      endPoint.dy, // 固定的终点
    );

    /// 完成路径
    path.lineTo(size.width, 0);
    path.close();

    return path;
  }

  /**
   * shouldReclip 方法
   * 如果动画值发生变化，需要重新裁剪
   */
  @override
  bool shouldReclip(AnimatedWaveClipper oldClipper) =>
      oldClipper.animationValue != animationValue; // 比较动画值是否变化
}

/**
 * 斜切效果裁剪器
 * 功能：创建对角线斜切效果
 * 常用于现代风格的UI设计
 */
class DiagonalClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    /// 创建路径对象
    final path = Path();

    /// 1. 从左上角(0,0)开始
    /// 2. 画直线到左下角偏上的位置（留下50像素的斜切空间）
    path.lineTo(0, size.height - 50);

    /// 从左侧斜切点画直线到右下角
    path.lineTo(size.width, size.height);

    /// 从右下角画直线到右上角
    path.lineTo(size.width, 0);

    /// 闭合路径，形成斜切四边形
    path.close();

    return path;
  }

  @override
  bool shouldReclip(DiagonalClipper oldClipper) => false;
}

/**
 * 波浪形裁剪器
 * 功能：创建波浪形状的裁剪效果
 * 常用于页面底部装饰、进度条等
 */
class WaveClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    /// 创建路径对象
    final path = Path();

    /// 1. 从左上角(0,0)开始，默认起点
    /// 2. 画直线到左下角偏上的位置，创建波浪基线
    path.lineTo(0, size.height * 0.8);

    /// 创建第一个波浪曲线
    /// 使用二次贝塞尔曲线创建平滑波浪

    /// 第一个控制点：控制曲线弯曲程度
    /// 设置在组件1/4宽度处，底部位置
    var firstControlPoint = Offset(size.width / 4, size.height);

    /// 第一个终点：波浪的第一个谷底
    /// 设置在组件1/2宽度处，基线位置
    var firstEndPoint = Offset(size.width / 2, size.height * 0.8);

    /// 绘制第一个波浪曲线
    path.quadraticBezierTo(
      firstControlPoint.dx,
      firstControlPoint.dy, // 控制点
      firstEndPoint.dx,
      firstEndPoint.dy, // 终点
    );

    /// 创建第二个波浪曲线

    /// 第二个控制点：控制第二个波浪的弯曲
    /// 设置在组件3/4宽度处，比基线更高的位置
    var secondControlPoint = Offset(size.width * 3 / 4, size.height * 0.6);

    /// 第二个终点：波浪的第二个谷底
    /// 设置在组件右边缘，基线位置
    var secondEndPoint = Offset(size.width, size.height * 0.8);

    /// 绘制第二个波浪曲线
    path.quadraticBezierTo(
      secondControlPoint.dx,
      secondControlPoint.dy, // 控制点
      secondEndPoint.dx,
      secondEndPoint.dy, // 终点
    );

    /// 从波浪终点画直线到右上角
    path.lineTo(size.width, 0);

    /// 闭合路径，完成波浪形状
    path.close();

    return path;
  }

  /// shouldReclip 方法
  /// 波浪形状固定，不需要重新裁剪
  @override
  bool shouldReclip(WaveClipper oldClipper) => false;
}

class RoundedClipper extends CustomClipper<Path> {
  final double borderRadius;

  RoundedClipper({this.borderRadius = 20.0});

  @override
  Path getClip(Size size) {
    final path = Path();
    path.addRRect(
      RRect.fromRectAndRadius(
        Rect.fromLTWH(0, 0, size.width, size.height),
        Radius.circular(borderRadius),
      ),
    );
    return path;
  }

  @override
  bool shouldReclip(RoundedClipper oldClipper) =>
      oldClipper.borderRadius != borderRadius;
}

class TriangleClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    final path = Path();
    path.moveTo(size.width / 2, 0); // 移动到顶部中间
    path.lineTo(size.width, size.height); // 到底部右边
    path.lineTo(0, size.height); // 到底部左边
    path.close(); // 闭合路径（回到起点）
    return path;
  }

  @override
  bool shouldReclip(TriangleClipper oldClipper) => false;
}
